package com.duobaoyu.dby.supply.biz.aspect;

import com.alibaba.fastjson.JSON;
import com.duobaoyu.dby.common.core.constant.RequestConstants;
import com.duobaoyu.dby.common.core.constant.StringPool;
import com.duobaoyu.dby.supply.biz.constant.SupplyChainConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName LoggerAspect
 * @Description 日志打印切面
 * @createTime 13:01:00 2022/06/28
 */
@Slf4j
@Aspect
@RequiredArgsConstructor
@Component
public class LoggerAspect {

	/**
	 * 换行符
	 */
	private static final String LINE_SEPARATOR = System.lineSeparator();

	@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
	public void logger() {

	}

	@Around("logger()")
	public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		long startTime = System.currentTimeMillis();
		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		String url = StringPool.EMPTY;
		if (Objects.nonNull(requestAttributes)) {
			HttpServletRequest request = requestAttributes.getRequest();
			url = Optional.of(request).map(HttpServletRequest::getRequestURL).map(StringBuffer::toString).orElse(StringPool.EMPTY);
			log.info("================================================= Start ====================================================");
			log.info("URL            : {}", Optional.of(request).map(HttpServletRequest::getRequestURL).map(StringBuffer::toString).orElse(StringPool.EMPTY));
			log.info("Http Method    : {}", Optional.of(request).map(HttpServletRequest::getMethod).orElse(StringPool.EMPTY));
			log.info("Class Method   : {}.{}", proceedingJoinPoint.getSignature().getDeclaringTypeName(), proceedingJoinPoint.getSignature().getName());
			log.info("IP             : {}", Optional.of(request).map(HttpServletRequest::getRemoteAddr).orElse(StringPool.EMPTY));
			log.info("Request Args   : {}", Arrays.toString(proceedingJoinPoint.getArgs()));
			log.info("Request Id     : {}", MDC.get(RequestConstants.REQUEST_ID));
			log.info("Biz Code       : {}", Optional.of(request).map(item -> item.getHeader(SupplyChainConstants.BIZ_CODE)).orElse(StringPool.EMPTY));
		}
		Object result;
		try {
			result = proceedingJoinPoint.proceed();
			if (Objects.nonNull(requestAttributes)) {
				if(log.isDebugEnabled()) {
					log.debug("Response Args   : {}", JSON.toJSONString(result));
				}
				log.info("Time-Consuming   : {} : {} ms", url, System.currentTimeMillis() - startTime);
				log.info("Version : {}", Optional.of(requestAttributes.getRequest()).map(request -> request.getHeader(SupplyChainConstants.SUPPLY_VERSION)).orElse(StringPool.EMPTY));
			}
		} catch (Throwable e) {
			log.warn("AfterThrow {}  : {}", proceedingJoinPoint, e.getMessage());
			log.warn("AfterThrow {}  : {}", proceedingJoinPoint, ExceptionUtils.getStackTrace(e));
			throw e;
		} finally {
			log.info("================================================= End ====================================================".concat(LINE_SEPARATOR));
		}
		return result;
	}
}
